#ifndef __ILIB_UTIL_LOGGER_H_20120331__
#define __ILIB_UTIL_LOGGER_H_20120331__

#include "../../iHeader.h"
#include "iStream.h"
#include "iLock.h"
#include "iSingleton.h"
#include "iThreadMgr.h"
#include "iThread.h"

enum LOGModule
{
	MOD_UTIL,
	MOD_TP,
    MOD_RESERVED = 16,
};

enum LOGLevel
{
	LVL_FATAL,
	LVL_ERROR,
	LVL_WARNING,
	LVL_INFO,
	LVL_DEBUG,
	LVL_FUNC
};
class iLogger
{
public:
    iLogger();
    /** @brief register a user defined module in logger
     *
     *  @Detail
     *      A user defined module name will be put in module column in trace file\n
     *  so that developpers can easy to filter out traces producted by their codes\n
     *  from trace files
     *
     *  @Paramters
     *      @param [in] module an unique indientify in process which from MOD_RESEVED
     *      @param [in] mname a person readable string to put in modue name column in trace file
     *      @param [in] ls a user defined stream to trace, if null use default
     *  
     *  @Return
     *      @return true if success
     *      @return false if the module id used by others already
     */
    bool register_module(uint8_t module, const char* mname, iLogStream* ls=NULL);
    void register_level (LOGLevel lv, const char* lname, iLogStream* ls=NULL);
    void open(const char* dir, const char* name);
    void log(uint8_t mid, uint8_t lid, uint32_t pid, uint32_t tid, const char* content);

private:
    struct nstm 
    { 
        char name[8]; 
        iLogStream* stm; 
        nstm():stm(NULL){name[0]=0;}
    };
    nstm* m_modules[256];
    nstm* m_levels[256];
	uint8_t		m_level;
	iLogStream	m_log_stream;
	iLock		m_lock;
};


#define INIT_LOGGER(d,n) \
{\
	iSingleton<iLogger>::instance()->register_module(MOD_UTIL, "UTIL");\
	iSingleton<iLogger>::instance()->register_module(MOD_TP  , "TP  ");\
	iSingleton<iLogger>::instance()->register_level(LVL_FATAL, "FATAL");\
	iSingleton<iLogger>::instance()->register_level(LVL_ERROR, "ERROR");\
	iSingleton<iLogger>::instance()->register_level(LVL_WARNING, "WARNING");\
	iSingleton<iLogger>::instance()->register_level(LVL_INFO , "INFO");\
	iSingleton<iLogger>::instance()->register_level(LVL_DEBUG, "DEBUG");\
	iSingleton<iLogger>::instance()->register_level(LVL_FUNC , "FUNC");\
	iSingleton<iLogger>::instance()->open(d, n);\
}\

#define LOG(m, l, x) iSingleton<iLogger>::instance()->log(m, l, iThreadMgr::get_process_id(), iThreadMgr::spawn_this()->get_id(), (x));
class _func_trace_ 
{
public:
	inline _func_trace_(uint8_t mod, const char* fn):m_mod(mod),func_name(fn)
	{
		std::stringstream ss;
		ss << func_name <<" Enter";
		LOG(m_mod, LVL_FUNC, ss.str().c_str());
	} 
	inline ~_func_trace_()
	{
		std::stringstream ss;
		ss<<func_name<<" Leave";
		LOG(m_mod, LVL_FUNC, ss.str().c_str());
	}

private:
    uint32_t    m_mod;
	const char* func_name;
};

#define iFUNC(m,x) \
	_func_trace_ _$this$_(m,x);

#define iDEBUG(m,x) \
{\
	std::stringstream ss;\
	ss<<x;\
	LOG(m, LVL_DEBUG, ss.str().c_str());\
}
#define iINFO(m,x) \
{\
	std::stringstream ss;\
	ss<<x;\
	LOG(m,LVL_INFO,ss.str().c_str())\
}
#define iWARNING(m,x) \
{\
    std::stringstream ss;\
    ss<<x;\
    LOG(MOD_UTIL,LVL_WARNING,ss.str().c_str())\
}
#define iERROR(m,x) \
{\
    std::stringstream ss;\
    ss<<x;\
    LOG(m,LVL_ERROR,ss.str().c_str())\
}
#endif  //__ILIB_UTIL_LOGGER_H_20120331__
